home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Format 1995 June
/
MacFormat 25.iso
/
Shareware City
/
Developers
/
OutOfPhase1.1 Source
/
OutOfPhase Folder
/
Fractions.c
< prev
next >
Wrap
Text File
|
1994-08-15
|
14KB
|
353 lines
/* Fractions.c */
/*****************************************************************************/
/* */
/* Out Of Phase: Digital Music Synthesis on General Purpose Computers */
/* Copyright (C) 1994 Thomas R. Lawrence */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* */
/* Thomas R. Lawrence can be reached at tomlaw@world.std.com. */
/* */
/*****************************************************************************/
#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"
#include "Fractions.h"
#include "Factoring.h"
/* note: this module does NOT deal with negative numbers!!! */
/* convert a decimal number to a fraction with the specified denominator limit */
void Double2Fraction(double Value, unsigned long Denominator,
FractionRec* Fraction)
{
ERROR(Value < 0,PRERR(ForceAbort,"Double2Fraction: value is less than zero"));
Fraction->Denominator = Denominator;
Fraction->Integer = Value;
Fraction->Fraction = (Value - Fraction->Integer) * Denominator + 0.5;
ReduceFraction(Fraction);
}
/* convert fraction to a double */
double Fraction2Double(FractionRec* Fraction)
{
ERROR(Fraction->Fraction >= Fraction->Denominator,PRERR(ForceAbort,
"Fraction2Double: numerator is larger than denominator"));
return Fraction->Integer + ((double)Fraction->Fraction / Fraction->Denominator);
}
/* add fractions. Destination fraction can be one of the source fractions */
void AddFractions(FractionRec* Left, FractionRec* Right, FractionRec* Dest)
{
unsigned long FractionTemp;
unsigned long DenominatorTemp;
unsigned long IntegerTemp;
ERROR(Left->Fraction >= Left->Denominator,PRERR(ForceAbort,
"AddFractions: numerator is larger than denominator"));
ERROR(Right->Fraction >= Right->Denominator,PRERR(ForceAbort,
"AddFractions: numerator is larger than denominator"));
/* add fractional parts */
#if !DEBUG
if (Left->Denominator == Right->Denominator)
{
/* if the denominators are the same, then adding is really easy */
DenominatorTemp = Left->Denominator;
FractionTemp = Left->Fraction + Right->Fraction;
}
else
#endif
{
unsigned long GCF;
/* if the denominators are not the same, then we need to multiply each */
/* side by some number so that they will be the same. finding the greatest */
/* common factor helps us find the smallest number to multiply by. */
/* Left->Denominator / GCF = the factors that left has which right needs. */
/* Right->Denominator / GCF = the factors that right has which left needs. */
GCF = FindCommonFactors(Left->Denominator,Right->Denominator);
/* by multiplying the denominators together, then dividing out the extra */
/* set of common factors, we find the smallest common denominator. The */
/* division is performed inside to prevent overflow */
DenominatorTemp = (Left->Denominator / GCF) * Right->Denominator;
/* the left and right sides should yield the same denominator */
ERROR(DenominatorTemp != (Right->Denominator / GCF) * Left->Denominator,
PRERR(ForceAbort,"AddFractions: couldn't factor denominators"));
/* since we are multiplying each fraction by N/N, we need to multiply */
/* the numerators by the same thing we multiplied the denominators by. */
FractionTemp = Left->Fraction * (Right->Denominator / GCF)
+ Right->Fraction * (Left->Denominator / GCF);
}
/* add the integer components */
IntegerTemp = Left->Integer + Right->Integer;
/* if there was an overflow in the fractional part, carry it to the integer */
if (FractionTemp >= DenominatorTemp)
{
/* since we are adding, the amount of carry should never be more than 1 */
FractionTemp -= DenominatorTemp;
IntegerTemp += 1;
}
ERROR(FractionTemp >= DenominatorTemp,PRERR(ForceAbort,
"AddFractions: numerator is larger than denominator after reduction"));
/* store result */
Dest->Integer = IntegerTemp;
Dest->Fraction = FractionTemp;
Dest->Denominator = DenominatorTemp;
}
/* test to see if the left is greater than the right */
MyBoolean FracGreaterThan(FractionRec* Left, FractionRec* Right)
{
ERROR(Left->Fraction >= Left->Denominator,PRERR(ForceAbort,
"FracGreaterThan: numerator is larger than denominator"));
ERROR(Right->Fraction >= Right->Denominator,PRERR(ForceAbort,
"FracGreaterThan: numerator is larger than denominator"));
if (Left->Integer > Right->Integer)
{
/* if the integer portion is bigger, then there's no contest */
return True;
}
else if (Left->Integer < Right->Integer)
{
/* same as above */
return False;
}
else
{
/* if the integer portions are the same, then we have to compare the */
/* fractional portions */
#if !DEBUG
if (Left->Denominator == Right->Denominator)
{
/* if the denominators are the same, then comparison is easy */
return Left->Fraction > Right->Fraction;
}
else
#endif
{
unsigned long GCF;
/* if the denominators are not the same, then they have to be */
/* made the same. as before, the GCF is the factors that are */
/* common to both sides. Left->Denominator / GCF is the portion of */
/* the left that right needs and Right->Denominator / GCF is the portion */
/* of the right that left needs. We don't care about the new */
/* denominator, but we will compare the new numerators. */
GCF = FindCommonFactors(Left->Denominator,Right->Denominator);
return Left->Fraction * (Right->Denominator / GCF)
> Right->Fraction * (Left->Denominator / GCF);
}
}
}
/* test to see if the left is greater than or equal to the right */
MyBoolean FracGreaterEqual(FractionRec* Left, FractionRec* Right)
{
ERROR(Left->Fraction >= Left->Denominator,PRERR(ForceAbort,
"FracGreaterThan: numerator is larger than denominator"));
ERROR(Right->Fraction >= Right->Denominator,PRERR(ForceAbort,
"FracGreaterThan: numerator is larger than denominator"));
if (Left->Integer > Right->Integer)
{
/* if the integer portion is bigger, then there's no contest */
return True;
}
else if (Left->Integer < Right->Integer)
{
/* same as above */
return False;
}
else
{
/* if the integer portions are the same, then we have to compare the */
/* fractional portions */
#if !DEBUG
if (Left->Denominator == Right->Denominator)
{
/* if the denominators are the same, then comparison is easy */
return Left->Fraction >= Right->Fraction;
}
else
#endif
{
unsigned long GCF;
/* if the denominators are not the same, then they have to be */
/* made the same. as before, the GCF is the factors that are */
/* common to both sides. Left->Denominator / GCF is the portion of */
/* the left that right needs and Right->Denominator / GCF is the portion */
/* of the right that left needs. We don't care about the new */
/* denominator, but we will compare the new numerators. */
GCF = FindCommonFactors(Left->Denominator,Right->Denominator);
return Left->Fraction * (Right->Denominator / GCF)
>= Right->Fraction * (Left->Denominator / GCF);
}
}
}
/* test fractions for equality */
MyBoolean FractionsEqual(FractionRec* Left, FractionRec* Right)
{
ERROR(Left->Fraction >= Left->Denominator,PRERR(ForceAbort,
"FractionsEqual: numerator is larger than denominator"));
ERROR(Right->Fraction >= Right->Denominator,PRERR(ForceAbort,
"FractionsEqual: numerator is larger than denominator"));
if (Left->Integer != Right->Integer)
{
/* if the integers aren't equal, then it's easy */
return False;
}
else
{
#if !DEBUG
/* if the integer portions are the same, then we have to compare the */
/* fractional portions */
if (Left->Denominator == Right->Denominator)
{
/* if the denominators are the same, then comparison is easy */
return Left->Fraction == Right->Fraction;
}
else
#endif
{
unsigned long GCF;
/* if the denominators are not the same, then they have to be */
/* made the same. as before, the GCF is the factors that are */
/* common to both sides. Left->Denominator / GCF is the portion of */
/* the left that right needs and Right->Denominator / GCF is the portion */
/* of the right that left needs. We don't care about the new */
/* denominator, but we will compare the new numerators. */
GCF = FindCommonFactors(Left->Denominator,Right->Denominator);
return Left->Fraction * (Right->Denominator / GCF)
== Right->Fraction * (Left->Denominator / GCF);
}
}
}
/* reduce fraction */
void ReduceFraction(FractionRec* Frac)
{
unsigned long GCF;
ERROR(Frac->Fraction >= Frac->Denominator,PRERR(ForceAbort,
"ReduceFraction: numerator is larger than denominator"));
GCF = FindCommonFactors(Frac->Fraction,Frac->Denominator);
Frac->Fraction = Frac->Fraction / GCF;
Frac->Denominator = Frac->Denominator / GCF;
}
/* multiply fractions. destination can be one of the sources */
/* this function will fail on numbers considerably smaller than the */
/* range of representable fractions. */
void MultFractions(FractionRec* Left, FractionRec* Right, FractionRec* Dest)
{
unsigned long Numerator;
unsigned long Denominator;
ERROR(Left->Fraction >= Left->Denominator,PRERR(ForceAbort,
"MultFractions: numerator is larger than denominator"));
ERROR(Right->Fraction >= Right->Denominator,PRERR(ForceAbort,
"MultFractions: numerator is larger than denominator"));
/* the product of two fractions: A/B * C/D == AC/BD */
/* here we multiply the denominators */
Denominator = Left->Denominator * Right->Denominator;
/* here we multiply the numerators and convert the integer parts into */
/* part of the numerator */
Numerator = (Left->Integer + Right->Integer) * Denominator
+ Left->Fraction * Right->Denominator
+ Right->Fraction * Left->Denominator;
/* division gives us the integer part back and the remainder is the numerator */
Dest->Integer = Numerator / Denominator;
Dest->Fraction = Numerator % Denominator;
Dest->Denominator = Denominator;
/* since we multiplied, reduce so that denominators don't get out of hand */
ReduceFraction(Dest);
}
/* subtract second fraction from first. Destination can be one of the sources */
void SubFractions(FractionRec* Left, FractionRec* Right, FractionRec* Dest)
{
long FractionTemp;
long DenominatorTemp;
long IntegerTemp;
ERROR(Left->Fraction >= Left->Denominator,PRERR(ForceAbort,
"AddFractions: numerator is larger than denominator"));
ERROR(Right->Fraction >= Right->Denominator,PRERR(ForceAbort,
"AddFractions: numerator is larger than denominator"));
/* add fractional parts */
#if !DEBUG
if (Left->Denominator == Right->Denominator)
{
/* if the denominators are the same, then adding is really easy */
DenominatorTemp = Left->Denominator;
FractionTemp = Left->Fraction - Right->Fraction;
}
else
#endif
{
unsigned long GCF;
/* if the denominators are not the same, then we need to multiply each */
/* side by some number so that they will be the same. finding the greatest */
/* common factor helps us find the smallest number to multiply by. */
/* Left->Denominator / GCF = the factors that left has which right needs. */
/* Right->Denominator / GCF = the factors that right has which left needs. */
GCF = FindCommonFactors(Left->Denominator,Right->Denominator);
/* by multiplying the denominators together, then dividing out the extra */
/* set of common factors, we find the smallest common denominator. The */
/* division is performed inside to prevent overflow */
DenominatorTemp = (Left->Denominator / GCF) * Right->Denominator;
/* the left and right sides should yield the same denominator */
ERROR(DenominatorTemp != (Right->Denominator / GCF) * Left->Denominator,
PRERR(ForceAbort,"AddFractions: couldn't factor denominators"));
/* since we are multiplying each fraction by N/N, we need to multiply */
/* the numerators by the same thing we multiplied the denominators by. */
FractionTemp = Left->Fraction * (Right->Denominator / GCF)
- Right->Fraction * (Left->Denominator / GCF);
}
/* add the integer components */
IntegerTemp = Left->Integer - Right->Integer;
/* if there was an overflow in the fractional part, carry it to the integer */
ERROR(FractionTemp >= DenominatorTemp,
PRERR(AllowResume,"SubFractions: overflow occurred when it shouldn't"));
if (FractionTemp < 0)
{
/* since we are adding, the amount of carry should never be more than 1 */
FractionTemp += DenominatorTemp;
IntegerTemp -= 1;
}
ERROR(FractionTemp < 0,PRERR(ForceAbort,
"SubFractions: numerator is way too small"));
/* store result */
Dest->Integer = IntegerTemp;
Dest->Fraction = FractionTemp;
Dest->Denominator = DenominatorTemp;
}